#include "serveur.h"

int creationSocket_Serveur(const char * port) {
  struct addrinfo hints;
  struct addrinfo * result, * rp;
  int res, bon, sock_err, s;
    
  memset(&hints, 0, sizeof(struct addrinfo));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;
  
  res = getaddrinfo(NULL, port, &hints, &result);
  if(res != 0)
    {
      fprintf(stderr, "getaddinfo:%s\n",gai_strerror(res));
      exit(1);
    }
  
  bon = 0;
  for( rp = result; rp != NULL; rp = rp->ai_next){
    s = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
    if( s == -1) 
      {
	fprintf(stderr, "Création de la socket impossible\n");
	continue;
      }
    res = bind(s , rp->ai_addr, rp->ai_addrlen);
    if (res == 0)
      {
	bon = 1;
	break;
      }
    fprintf(stderr, "Impossible de réserver l'adresse\n");
    close(s);
  }
  freeaddrinfo(result);
  if (bon == 0)
    {
      fprintf(stderr, "Impossible d'obtenir une adresse\n");
      exit(1);
    }
  
  sock_err = listen(s, 5);
  
  if(sock_err == -1)
    {
      perror("listen");
      close(s);
      exit(1);
    }
  
  return s;
}

int attenteConnexion_Serveur(int socket)
{
  int t, res;
  struct sockaddr_storage taddr;
  socklen_t taddrlen = sizeof(taddr);
  char hname[NI_MAXHOST], sname [NI_MAXSERV];

  fprintf(stdout, "Attente de connexion\n");

  t = accept(socket, (struct sockaddr *)&taddr, &taddrlen);
  printf("Connexion en cours...\n");
  res = getnameinfo((struct sockaddr *)&taddr, taddrlen,
		    hname, NI_MAXHOST,
		    sname, NI_MAXSERV,
		    NI_NUMERICSERV);
  if(res !=0) {
    fprintf(stderr, "getnameinfo : %s\n", gai_strerror(res));
    exit(1);
  }
  
  printf ("La socket %d a eu un client depuis %s sur le port %s\n", socket , hname, sname);

  return t;
}

void reception_Utilisateur(char **utilisateur, int socket)
{
  size_t tailleUti = 0;
  int tailleReception = 0;
  int ret = 0;
  fd_set rfds, rfds_tot;
  if((*utilisateur))
    {
      free(*utilisateur);
      (*utilisateur) = NULL;
    }
  FD_ZERO(&rfds_tot);
  FD_SET(socket, &rfds_tot);
  FD_ZERO(&rfds);
  rfds = rfds_tot;
  if(select(FD_SETSIZE, &rfds, NULL, NULL, NULL) == -1)
    {
      if(errno != EINTR)
	{
	  perror("select");
	  exit(1);
	}
    }
  if(FD_ISSET(socket, &rfds))
    {
      if(recv(socket, &tailleUti, sizeof(size_t), 0) == -1)
	{
	  perror("Erreur recv");
	  exit(1);
	}
      (*utilisateur) = (char *) malloc( (tailleUti+1)*sizeof(char));
      if((*utilisateur) == NULL)
	{
	  fprintf(stderr, "Erreur malloc\n");
	  exit(1);
	}
      do
	{
	  FD_ZERO(&rfds);
	  rfds = rfds_tot;
	  if(select(FD_SETSIZE, &rfds, NULL, NULL, NULL) == -1)
	    {
	      if(errno != EINTR)
		{
		  perror("select");
		  exit(1);
		}
	    }
	  if(FD_ISSET(socket, &rfds))
	    {
	      ret = recv(socket, (&(*utilisateur)[tailleReception]), (tailleUti-tailleReception) * sizeof(char), 0);
	      if(ret == -1)
		{
		  perror("Erreur recv");
		  exit(1);
		}
	      tailleReception += ret;
	    }
	  else
	    break;
	}while(tailleReception < tailleUti && VARSIGNAL);
      (*utilisateur)[tailleReception] = '\0';
      printf("Nouvel utilisateur : %s\n", *utilisateur);
    }
}

void attenteCommande_Serveur(int socket)
{
  char reception = 'S';
  char continu = 1;
  char *utilisateur = NULL;
  int retval = 0;
  fd_set rfds, rfds_tot;

  reception_Utilisateur(&utilisateur, socket);
  FD_ZERO(&rfds_tot);
  FD_SET(socket, &rfds_tot);
  while(continu && VARSIGNAL)
  {
    FD_ZERO(&rfds);
    rfds = rfds_tot;

    printf("Attente commande client...\n");
    fflush(stdout);
    retval = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
    if(retval == -1)
      {
	if(errno == EINTR)
	  break;
	perror("select");
	exit(1);
      }
    if(FD_ISSET(socket, &rfds))
      {
	if(recv(socket, &reception, sizeof(char), 0) == -1)
	  {
	    if(errno == ENOBUFS)
	      break;
	    perror("Erreur recv");
	    exit(1);
	  }
	switch(reception)
	  {
	  case 'R':
	    printf("Envoie du fichier\n");
	    envoyer_Rapport(socket, utilisateur);
	    break;
	  case 'E':
	    printf("Reception du fichier\n");
	    recevoir_Rapport(socket, utilisateur);
	    break;
	  case 'C':
	    printf("Changement d'utilisateur\n");
	    reception_Utilisateur(&utilisateur, socket);
	    break;
	  case 'S':
	    printf("Fin de la transaction\n");
	    continu = 0;
	    break;
	  default:
	    printf("Erreur\n");
	    break;
	  }
      }
    if(VARSIGNAL == 0)
      {
	/* Réception d'un signal d'arrêt, clôture de la connexion */
	fprintf(stderr, "Reception d'un signal d'arrêt\n");
	break;
      }
  }
  
  free(utilisateur);
  close(socket);
}
